home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
007
/
xlisp16.arc
/
XLMATH.C
< prev
next >
Wrap
Text File
|
1985-12-21
|
11KB
|
527 lines
/* xlmath - xlisp builtin arithmetic functions */
/* Copyright (c) 1985, by David Michael Betz
All Rights Reserved
Permission is granted for unrestricted non-commercial use */
#include "xlisp.h"
#ifdef MEGAMAX
#include <fmath.h>
overlay "math"
#else
#include <math.h>
#endif
/* external variables */
extern NODE *true;
/* forward declarations */
FORWARD NODE *unary();
FORWARD NODE *binary();
FORWARD NODE *predicate();
FORWARD NODE *compare();
/* xadd - builtin function for addition */
NODE *xadd(args)
NODE *args;
{
return (binary(args,'+'));
}
/* xsub - builtin function for subtraction */
NODE *xsub(args)
NODE *args;
{
return (binary(args,'-'));
}
/* xmul - builtin function for multiplication */
NODE *xmul(args)
NODE *args;
{
return (binary(args,'*'));
}
/* xdiv - builtin function for division */
NODE *xdiv(args)
NODE *args;
{
return (binary(args,'/'));
}
/* xrem - builtin function for remainder */
NODE *xrem(args)
NODE *args;
{
return (binary(args,'%'));
}
/* xmin - builtin function for minimum */
NODE *xmin(args)
NODE *args;
{
return (binary(args,'m'));
}
/* xmax - builtin function for maximum */
NODE *xmax(args)
NODE *args;
{
return (binary(args,'M'));
}
/* xexpt - built-in function 'expt' */
NODE *xexpt(args)
NODE *args;
{
return (binary(args,'E'));
}
/* xbitand - builtin function for bitwise and */
NODE *xbitand(args)
NODE *args;
{
return (binary(args,'&'));
}
/* xbitior - builtin function for bitwise inclusive or */
NODE *xbitior(args)
NODE *args;
{
return (binary(args,'|'));
}
/* xbitxor - builtin function for bitwise exclusive or */
NODE *xbitxor(args)
NODE *args;
{
return (binary(args,'^'));
}
/* binary - handle binary operations */
LOCAL NODE *binary(args,fcn)
NODE *args; int fcn;
{
FIXNUM ival,iarg;
FLONUM fval,farg;
NODE *arg;
int imode;
/* get the first argument */
arg = xlarg(&args);
/* set the type of the first argument */
if (fixp(arg)) {
ival = getfixnum(arg);
imode = TRUE;
}
else if (floatp(arg)) {
fval = getflonum(arg);
imode = FALSE;
}
else
xlerror("bad argument type",arg);
/* treat '-' with a single argument as a special case */
if (fcn == '-' && args == NIL)
if (imode)
ival = -ival;
else
fval = -fval;
/* handle each remaining argument */
while (args) {
/* get the next argument */
arg = xlarg(&args);
/* check its type */
if (fixp(arg))
if (imode) iarg = getfixnum(arg);
else farg = (FLONUM)getfixnum(arg);
else if (floatp(arg))
if (imode) { fval = (FLONUM)ival; farg = getflonum(arg); imode = FALSE; }
else farg = getflonum(arg);
else
xlerror("bad argument type",arg);
/* accumulate the result value */
if (imode)
switch (fcn) {
case '+': ival += iarg; break;
case '-': ival -= iarg; break;
case '*': ival *= iarg; break;
case '/': checkizero(iarg); ival /= iarg; break;
case '%': checkizero(iarg); ival %= iarg; break;
case 'M': if (iarg > ival) ival = iarg; break;
case 'm': if (iarg < ival) ival = iarg; break;
case '&': ival &= iarg; break;
case '|': ival |= iarg; break;
case '^': ival ^= iarg; break;
default: badiop();
}
else
switch (fcn) {
case '+': fval += farg; break;
case '-': fval -= farg; break;
case '*': fval *= farg; break;
case '/': checkfzero(farg); fval /= farg; break;
case 'M': if (farg > fval) fval = farg; break;
case 'm': if (farg < fval) fval = farg; break;
case 'E': fval = pow(fval,farg); break;
default: badfop();
}
}
/* return the result */
return (imode ? cvfixnum(ival) : cvflonum(fval));
}
/* checkizero - check for integer division by zero */
checkizero(iarg)
FIXNUM iarg;
{
if (iarg == 0)
xlfail("division by zero");
}
/* checkfzero - check for floating point division by zero */
checkfzero(farg)
FLONUM farg;
{
if (farg == 0.0)
xlfail("division by zero");
}
/* checkfneg - check for square root of a negative number */
checkfneg(farg)
FLONUM farg;
{
if (farg < 0.0)
xlfail("square root of a negative number");
}
/* xbitnot - bitwise not */
NODE *xbitnot(args)
NODE *args;
{
return (unary(args,'~'));
}
/* xabs - builtin function for absolute value */
NODE *xabs(args)
NODE *args;
{
return (unary(args,'A'));
}
/* xadd1 - builtin function for adding one */
NODE *xadd1(args)
NODE *args;
{
return (unary(args,'+'));
}
/* xsub1 - builtin function for subtracting one */
NODE *xsub1(args)
NODE *args;
{
return (unary(args,'-'));
}
/* xsin - built-in function 'sin' */
NODE *xsin(args)
NODE *args;
{
return (unary(args,'S'));
}
/* xcos - built-in function 'cos' */
NODE *xcos(args)
NODE *args;
{
return (unary(args,'C'));
}
/* xtan - built-in function 'tan' */
NODE *xtan(args)
NODE *args;
{
return (unary(args,'T'));
}
/* xexp - built-in function 'exp' */
NODE *xexp(args)
NODE *args;
{
return (unary(args,'E'));
}
/* xsqrt - built-in function 'sqrt' */
NODE *xsqrt(args)
NODE *args;
{
return (unary(args,'R'));
}
/* xfix - built-in function 'fix' */
NODE *xfix(args)
NODE *args;
{
return (unary(args,'I'));
}
/* xfloat - built-in function 'float' */
NODE *xfloat(args)
NODE *args;
{
return (unary(args,'F'));
}
/* xrand - built-in function 'random' */
NODE *xrand(args)
NODE *args;
{
return (unary(args,'R'));
}
/* unary - handle unary operations */
LOCAL NODE *unary(args,fcn)
NODE *args; int fcn;
{
FLONUM fval;
FIXNUM ival;
NODE *arg;
/* get the argument */
arg = xlarg(&args);
xllastarg(args);
/* check its type */
if (fixp(arg)) {
ival = getfixnum(arg);
switch (fcn) {
case '~': ival = ~ival; break;
case 'A': ival = abs(ival); break;
case '+': ival++; break;
case '-': ival--; break;
case 'I': break;
case 'F': return (cvflonum((FLONUM)ival));
case 'R': ival = (FIXNUM)osrand((int)ival); break;
default: badiop();
}
return (cvfixnum(ival));
}
else if (floatp(arg)) {
fval = getflonum(arg);
switch (fcn) {
case 'A': fval = fabs(fval); break;
case '+': fval += 1.0; break;
case '-': fval -= 1.0; break;
case 'S': fval = sin(fval); break;
case 'C': fval = cos(fval); break;
case 'T': fval = tan(fval); break;
case 'E': fval = exp(fval); break;
case 'R': checkfneg(fval); fval = sqrt(fval); break;
case 'I': return (cvfixnum((FIXNUM)fval));
case 'F': break;
default: badfop();
}
return (cvflonum(fval));
}
else
xlerror("bad argument type",arg);
}
/* xminusp - is this number negative? */
NODE *xminusp(args)
NODE *args;
{
return (predicate(args,'-'));
}
/* xzerop - is this number zero? */
NODE *xzerop(args)
NODE *args;
{
return (predicate(args,'Z'));
}
/* xplusp - is this number positive? */
NODE *xplusp(args)
NODE *args;
{
return (predicate(args,'+'));
}
/* xevenp - is this number even? */
NODE *xevenp(args)
NODE *args;
{
return (predicate(args,'E'));
}
/* xoddp - is this number odd? */
NODE *xoddp(args)
NODE *args;
{
return (predicate(args,'O'));
}
/* predicate - handle a predicate function */
LOCAL NODE *predicate(args,fcn)
NODE *args; int fcn;
{
FLONUM fval;
FIXNUM ival;
NODE *arg;
/* get the argument */
arg = xlarg(&args);
xllastarg(args);
/* check the argument type */
if (fixp(arg)) {
ival = getfixnum(arg);
switch (fcn) {
case '-': ival = (ival < 0); break;
case 'Z': ival = (ival == 0); break;
case '+': ival = (ival > 0); break;
case 'E': ival = ((ival & 1) == 0); break;
case 'O': ival = ((ival & 1) != 0); break;
default: badiop();
}
}
else if (floatp(arg)) {
fval = getflonum(arg);
switch (fcn) {
case '-': ival = (fval < 0); break;
case 'Z': ival = (fval == 0); break;
case '+': ival = (fval > 0); break;
default: badfop();
}
}
else
xlerror("bad argument type",arg);
/* return the result value */
return (ival ? true : NIL);
}
/* xlss - builtin function for < */
NODE *xlss(args)
NODE *args;
{
return (compare(args,'<'));
}
/* xleq - builtin function for <= */
NODE *xleq(args)
NODE *args;
{
return (compare(args,'L'));
}
/* equ - builtin function for = */
NODE *xequ(args)
NODE *args;
{
return (compare(args,'='));
}
/* xneq - builtin function for /= */
NODE *xneq(args)
NODE *args;
{
return (compare(args,'#'));
}
/* xgeq - builtin function for >= */
NODE *xgeq(args)
NODE *args;
{
return (compare(args,'G'));
}
/* xgtr - builtin function for > */
NODE *xgtr(args)
NODE *args;
{
return (compare(args,'>'));
}
/* compare - common compare function */
LOCAL NODE *compare(args,fcn)
NODE *args; int fcn;
{
NODE *arg1,*arg2;
FIXNUM icmp;
FLONUM fcmp;
int imode;
/* get the two arguments */
arg1 = xlarg(&args);
arg2 = xlarg(&args);
xllastarg(args);
/* do the compare */
if (stringp(arg1) && stringp(arg2)) {
icmp = strcmp(getstring(arg1),getstring(arg2));
imode = TRUE;
}
else if (fixp(arg1) && fixp(arg2)) {
icmp = getfixnum(arg1) - getfixnum(arg2);
imode = TRUE;
}
else if (floatp(arg1) && floatp(arg2)) {
fcmp = getflonum(arg1) - getflonum(arg2);
imode = FALSE;
}
else if (fixp(arg1) && floatp(arg2)) {
fcmp = (FLONUM)getfixnum(arg1) - getflonum(arg2);
imode = FALSE;
}
else if (floatp(arg1) && fixp(arg2)) {
fcmp = getflonum(arg1) - (FLONUM)getfixnum(arg2);
imode = FALSE;
}
else
xlfail("expecting strings, integers or floats");
/* compute result of the compare */
if (imode)
switch (fcn) {
case '<': icmp = (icmp < 0); break;
case 'L': icmp = (icmp <= 0); break;
case '=': icmp = (icmp == 0); break;
case '#': icmp = (icmp != 0); break;
case 'G': icmp = (icmp >= 0); break;
case '>': icmp = (icmp > 0); break;
}
else
switch (fcn) {
case '<': icmp = (fcmp < 0.0); break;
case 'L': icmp = (fcmp <= 0.0); break;
case '=': icmp = (fcmp == 0.0); break;
case '#': icmp = (fcmp != 0.0); break;
case 'G': icmp = (fcmp >= 0.0); break;
case '>': icmp = (fcmp > 0.0); break;
}
/* return the result */
return (icmp ? true : NIL);
}
/* badiop - bad integer operation */
LOCAL badiop()
{
xlfail("bad integer operation");
}
/* badfop - bad floating point operation */
LOCAL badfop()
{
xlfail("bad floating point operation");
}